1   /*
2    * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /*
25   * @test
26   * @bug 4832224 6322584 6328478 6328481 6322580 6588884 6587863
27   * @summary Verifies that the pixelization of simple primitives (drawLine,
28   * fillRect, drawRect, fill, draw) with the OGL pipeline enabled
29   * matches that produced by our software loops.  (The primitives tested here
30   * are simple enough that the OGL results should match the software results
31   * exactly.)  There is some overlap with PolyVertTest as we test both
32   * solid and XOR rendering here, but this testcase is a bit simpler and
33   * more appropriate for quick OGL testing.  This test is also useful for
34   * comparing quality between our X11/GDI and software pipelines.
35   * @run main/othervm SimplePrimQuality
36   * @run main/othervm -Dsun.java2d.opengl=True SimplePrimQuality
37   * @author campbelc
38   */
39  
40  import java.awt.*;
41  import java.awt.geom.*;
42  import java.awt.image.*;
43  import java.io.File;
44  import java.io.IOException;
45  import javax.imageio.ImageIO;
46  
47  public class SimplePrimQuality extends Canvas {
48  
49      private static final int SIZE = 300;
50      private static boolean done;
51      private static boolean testVI;
52      private static volatile BufferedImage capture;
53      private static void doCapture(Component test) {
54          // Grab the screen region
55          try {
56              Robot robot = new Robot();
57              Point pt1 = test.getLocationOnScreen();
58              Rectangle rect =
59                  new Rectangle(pt1.x, pt1.y, test.getWidth(), test.getHeight());
60              capture = robot.createScreenCapture(rect);
61          } catch (Exception e) {
62              e.printStackTrace();
63          }
64      }
65  
66      private static final int[][] rpts = {
67          {2, 0, 0, 0},
68          {12, 0, 1, 0},
69          {22, 0, 0, 1},
70          {32, 0, 1, 1},
71          {42, 0, 2, 1},
72          {52, 0, 1, 2},
73          {62, 0, 2, 2},
74          {72, 0, 5, 5},
75          {82, 0, 10, 10},
76          {97, 0, 15, 15},
77      };
78  
79      private void drawLine(Graphics2D g, int x, int y, int dx, int dy) {
80          g.drawLine(x, y, x + dx, y + dy);
81      }
82  
83      private void drawLines(Graphics2D g, int s) {
84          drawLine(g, 2, 0, 0, 0);
85          drawLine(g, 12, 0, 0, s);
86          drawLine(g, 22, 0, s, 0);
87          drawLine(g, 32, 0, s, s);
88          drawLine(g, 42, 0, 0, -s);
89          drawLine(g, 52, 0, -s, 0);
90          drawLine(g, 62, 0, -s, -s);
91          drawLine(g, 72, 0, -s, s);
92          drawLine(g, 82, 0, s, -s);
93      }
94  
95      private void fillRects(Graphics2D g) {
96          for (int i = 0; i < rpts.length; i++) {
97              g.fillRect(rpts[i][0], rpts[i][1], rpts[i][2], rpts[i][3]);
98          }
99      }
100 
101     private void drawRects(Graphics2D g) {
102         for (int i = 0; i < rpts.length; i++) {
103             g.drawRect(rpts[i][0], rpts[i][1], rpts[i][2], rpts[i][3]);
104         }
105     }
106 
107     private void fillOvals(Graphics2D g) {
108         for (int i = 0; i < rpts.length; i++) {
109             // use fill() instead of fillOval(), since the former is more
110             // likely to be consistent with our software loops when the
111             // OGL pipeline cannot be enabled
112             g.fill(new Ellipse2D.Float(rpts[i][0], rpts[i][1],
113                                        rpts[i][2], rpts[i][3]));
114         }
115     }
116 
117     private void drawOvals(Graphics2D g) {
118         for (int i = 0; i < rpts.length; i++) {
119             // use draw() instead of drawOval(), since the former is more
120             // likely to be consistent with our software loops when the
121             // OGL pipeline cannot be enabled
122             g.draw(new Ellipse2D.Float(rpts[i][0], rpts[i][1],
123                                        rpts[i][2], rpts[i][3]));
124         }
125     }
126 
127     private void renderShapes(Graphics2D g) {
128         // drawLine tests...
129         g.translate(0, 5);
130         drawLines(g, 1);
131         g.translate(0, 10);
132         drawLines(g, 4);
133 
134         // fillRect tests...
135         g.translate(0, 10);
136         fillRects(g);
137 
138         // drawRect tests...
139         g.translate(0, 20);
140         drawRects(g);
141 
142         // fillOval tests...
143         g.translate(0, 20);
144         fillOvals(g);
145 
146         // drawOval tests...
147         g.translate(0, 20);
148         drawOvals(g);
149     }
150 
151     private void renderTest(Graphics2D g, int w, int h) {
152         // on the left side, render the shapes in solid mode
153         g.setColor(Color.black);
154         g.fillRect(0, 0, w, h);
155         g.setColor(Color.green);
156         renderShapes(g);
157 
158         // on the right side, render the shapes in XOR mode
159         g.setTransform(AffineTransform.getTranslateInstance(SIZE/2, 0));
160         g.setXORMode(Color.black);
161         renderShapes(g);
162         g.setTransform(AffineTransform.getTranslateInstance(SIZE/2, 0));
163         renderShapes(g);
164     }
165 
166     public void paint(Graphics g) {
167 
168         Graphics2D g2d = (Graphics2D)g;
169         renderTest(g2d, SIZE, SIZE);
170 
171         Toolkit.getDefaultToolkit().sync();
172 
173         synchronized (this) {
174             if (!done) {
175                 doCapture(this);
176                 done = true;
177             }
178             notifyAll();
179         }
180     }
181 
182     public Dimension getPreferredSize() {
183         return new Dimension(SIZE, SIZE);
184     }
185 
186     public static void main(String[] args) {
187         boolean show = false;
188         for (String arg : args) {
189             if (arg.equals("-testvi")) {
190                 System.out.println("Testing VolatileImage, not screen");
191                 testVI = true;
192             } else if (arg.equals("-show")) {
193                 show = true;
194             }
195         }
196 
197         SimplePrimQuality test = new SimplePrimQuality();
198         Frame frame = new Frame();
199         frame.add(test);
200         frame.pack();
201         frame.setVisible(true);
202 
203         // Wait until the component's been painted
204         synchronized (test) {
205             while (!done) {
206                 try {
207                     test.wait();
208                 } catch (InterruptedException e) {
209                     throw new RuntimeException("Failed: Interrupted");
210                 }
211             }
212         }
213 
214         // REMIND: We will allow this test to pass silently on Windows
215         // (when OGL is not enabled) until we fix the GDI pipeline so that
216         // its stroked/filled GeneralPaths match our software loops (see
217         // 6322554).  This check should be removed when 6322554 is fixed.
218         GraphicsConfiguration gc = frame.getGraphicsConfiguration();
219         if (gc.getClass().getSimpleName().startsWith("Win")) {
220             System.out.println("GDI pipeline detected: " +
221                                "test considered PASSED");
222             frame.dispose();
223             return;
224         }
225 
226 
227         if (testVI) {
228             // render to a VI instead of the screen
229             VolatileImage vi = frame.createVolatileImage(SIZE, SIZE);
230             do {
231                 vi.validate(frame.getGraphicsConfiguration());
232                 Graphics2D g1 = vi.createGraphics();
233                 test.renderTest(g1, SIZE, SIZE);
234                 g1.dispose();
235                 capture = vi.getSnapshot();
236             } while (vi.contentsLost());
237             frame.dispose();
238         }
239 
240         if (!show) {
241             frame.dispose();
242         }
243         if (capture == null) {
244             throw new RuntimeException("Error capturing the rendering");
245         }
246 
247         // Create reference image
248         int w = SIZE, h = SIZE;
249         BufferedImage refimg = new BufferedImage(w, h,
250                                                  BufferedImage.TYPE_INT_RGB);
251         Graphics2D g = refimg.createGraphics();
252         test.renderTest(g, w, h);
253         g.dispose();
254 
255         // Test pixels
256         for (int y = 0; y < h; y++) {
257             for (int x = 0; x < w; x++) {
258                 int actual = capture.getRGB(x, y);
259                 int expected = refimg.getRGB(x, y);
260                 if (actual != expected) {
261                     String expectedName = "SimplePrimQuality_expected.png";
262                     String actualName = "SimplePrimQuality_actual.png";
263                     try {
264                         System.out.println("Writing expected image to: "+
265                                            expectedName);
266                         ImageIO.write(refimg, "png", new File(expectedName));
267                         System.out.println("Writing actual image   to: "+
268                                            actualName);
269                         ImageIO.write(capture, "png", new File(actualName));
270                     } catch (IOException ex) {}
271                     throw new RuntimeException("Test failed at x="+x+" y="+y+
272                                                " (expected="+
273                                                Integer.toHexString(expected) +
274                                                " actual="+
275                                                Integer.toHexString(actual) +
276                                                ")");
277                 }
278             }
279         }
280     }
281 }